﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

using GravityBallScreenSaver.Gravity;
using GravityBallScreenSaver.Bodies;

namespace GravityBallScreenSaver.Graphics
{    
    class GraphicsEngine : AGraphicsEngine
    {
        private double planetRadius = Properties.Settings.Default.PlanetDiameter / 2;
        private IGravity physicsController;
        // Create a collection of child visual objects.
        private VisualCollection _children;
        DrawingVisual drawingVisual = new DrawingVisual();

        public GraphicsEngine(int width, int height, IGravity physicsController)
        {
            this.physicsController = physicsController;
            //physicsController = new Gravity.Gravity(width, height)
            //physicsController.Step += OnGravityStep;

            //User timer inside of physics controller to animate the planets
            //physicsController.Start();

            _children = new VisualCollection(this);
            //_children.Add(CreateDrawingVisualRectangle());
            //_children.Add(CreateDrawingVisualText());
            //_children.Add(CreateDrawingVisualEllipses());
            _children.Add(CreateSystem());

            // Add the event handler for MouseLeftButtonUp.
            this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(GraphicsEngine_MouseLeftButtonUp);
        }
        // Capture the mouse event and hit test the coordinate point value against
        // the child visual objects.
        void GraphicsEngine_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            // Retreive the coordinates of the mouse button event.
            Point pt = e.GetPosition((UIElement)sender);

            // Initiate the hit test by setting up a hit test result callback method.
            VisualTreeHelper.HitTest(this, null, new HitTestResultCallback(myCallback), new PointHitTestParameters(pt));
        }

        // If a child visual object is hit, toggle its opacity to visually indicate a hit.
        public HitTestResultBehavior myCallback(HitTestResult result)
        {
            if (result.VisualHit.GetType() == typeof(DrawingVisual))
            {
                if (((DrawingVisual)result.VisualHit).Opacity == 1.0)
                {
                    ((DrawingVisual)result.VisualHit).Opacity = 0.4;
                }
                else
                {
                    ((DrawingVisual)result.VisualHit).Opacity = 1.0;
                }
            }

            // Stop the hit test enumeration of objects in the visual tree.
            return HitTestResultBehavior.Stop;
        }
        // Create a DrawingVisual that contains a rectangle.
        private DrawingVisual CreateDrawingVisualRectangle()
        {
            DrawingVisual drawingVisual = new DrawingVisual();

            // Retrieve the DrawingContext in order to create new drawing content.
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            // Create a rectangle and draw it in the DrawingContext.
            Rect rect = new Rect(new Point(160, 100), new Size(320, 80));
            drawingContext.DrawRectangle(Brushes.LightBlue, (Pen)null, rect);

            // Persist the drawing content.
            drawingContext.Close();

            return drawingVisual;
        }
        // Create a DrawingVisual that contains text.
        private DrawingVisual CreateDrawingVisualText()
        {
            // Create an instance of a DrawingVisual.
            DrawingVisual drawingVisual = new DrawingVisual();

            // Retrieve the DrawingContext from the DrawingVisual.
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            // Draw a formatted text string into the DrawingContext.
            drawingContext.DrawText(
               new FormattedText("Click Me!",
                  CultureInfo.GetCultureInfo("en-us"),
                  FlowDirection.LeftToRight,
                  new Typeface("Verdana"),
                  36, Brushes.Black),
                  new Point(200, 116));

            // Close the DrawingContext to persist changes to the DrawingVisual.
            drawingContext.Close();

            return drawingVisual;
        }

        // Create a DrawingVisual that contains an ellipse.
        private DrawingVisual CreateDrawingVisualEllipses()
        {
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            drawingContext.DrawEllipse(Brushes.Maroon, null, new Point(430, 136), 20, 20);
            drawingContext.Close();

            return drawingVisual;
        }
        // Provide a required override for the VisualChildrenCount property.
        protected override int VisualChildrenCount
        {
            get { return _children.Count; }
        }
        // Provide a required override for the GetVisualChild method.
        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index > _children.Count)
            {
                throw new ArgumentOutOfRangeException();
            }

            return _children[index];
        }

        private DrawingVisual CreateSystem()
        {            
            DrawingContext drawingContext = drawingVisual.RenderOpen();

            //First, draw trails
            //TODO:  Logic to draw trail
            //Second, draw Planets
            for (int i = 0; i < physicsController.planets.Length; i++)
            {
                Ball planet = physicsController.planets[i];

                Brush b = new SolidColorBrush(planet.baseColor);

                drawingContext.DrawEllipse(b, null, new Point(planet.Px0, planet.Py0), planetRadius, planetRadius);
                drawingContext.DrawText(new FormattedText(i.ToString() + " " + planet.Px0.ToString() + " " + planet.Py0.ToString(), CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Arial"), 24, b), new Point(50, 100 * i + 100));
            }
            drawingContext.Close();

            return drawingVisual;
        }

        private void OnGravityStep(object source, GravityEventArgs e)
        {
            //_children[0] = CreateSystem();
            //_children.Clear();
//            _children.Add(CreateSystem());
                        
            //CreateSystem();
        }
    }
}
